package org.nobject.common.lang;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.util.Random;

import static org.nobject.common.lang.ClassUtils.*;

import org.nobject.common.exception.ConvertException;

/**
 * 
 * 数字工具类
 *
 * @author bianrongjun
 * @version 1.0
 */
public class NumberUtils {
	
	/******************************************************************************************************************
	 * 
	 *  toNumber 区域
	 * 
	 *******************************************************************************************************************/
	
	/**
	 * 对象转换成byte
	 * @param o 对象
	 */
	public static byte toByte(Object o) throws ConvertException{
		if (o == null) return 0;
		Class c=o.getClass();
		if (isNumber(c)) return ((Number)o).byteValue();
		if (isString(c)) try{if(((String)o).equals("")) return 0;return Byte.valueOf((String)o);} catch (NumberFormatException e) {throw new ConvertException(e);}
		throw new ConvertException("不支持该类型到byte的转换:"+o.getClass().getName());
	}
	
	/**
	 * 对象转换成short
	 * @param o 对象
	 */
	public static float toShort(Object o) throws ConvertException {
		if (o == null) return 0;
		Class c=o.getClass();
		if (isNumber(c)) return ((Number)o).shortValue();
		if (isString(c)) try{if(((String)o).equals("")) return 0;return Short.valueOf((String)o);} catch (NumberFormatException e) {throw new ConvertException(e);}
		throw new ConvertException("不支持该类型到short的转换:"+o.getClass().getName());
	}
	
	/**
	 * 对象转换成Int
	 * @param o 对象
	 */
	public static int toInt(Object o) throws ConvertException {
		if (o == null) return 0;
		Class c=o.getClass();
		if (isNumber(c)) return ((Number)o).intValue();
		if (isString(c)) try {if(((String)o).equals("")) return 0;return Integer.valueOf((String)o);} catch (NumberFormatException e) {throw new ConvertException(e);}
		if (isBoolean(c)) try {if(((Boolean)o).equals(true)) return 1;return 0;} catch (NumberFormatException e) {throw new ConvertException(e);}
		throw new ConvertException("不支持该类型到int的转换:"+o.getClass().getName());
	}

	/**
	 * 对象转换成Long
	 * @param o 对象
	 */
	public static long toLong(Object o) throws ConvertException {
		if (o == null) return 0;
		Class c=o.getClass();
		if (isNumber(c)) return ((Number)o).longValue();
		if (isString(c)) try {if(((String)o).equals("")) return 0;return Long.valueOf((String)o);} catch (NumberFormatException e) {throw new ConvertException(e);}
		throw new ConvertException("不支持该类型到long的转换:"+o.getClass().getName());
	}

	/**
	 * 对象转换成Double
	 * @param o 对象
	 */
	public static double toDouble(Object o) throws ConvertException {
		if (o == null) return 0;
		Class c=o.getClass();
		if (isNumber(c)) return ((Number)o).doubleValue();
		if (isString(c)) try{if(((String)o).equals("")) return 0;return Double.valueOf((String)o);} catch (NumberFormatException e) {throw new ConvertException(e);}
		throw new ConvertException("不支持该类型到double的转换:"+o.getClass().getName());
	}

	/**
	 * 对象转换成Float
	 * @param o 对象
	 */
	public static float toFloat(Object o) throws ConvertException {
		if (o == null) return 0;
		Class c=o.getClass();
		if (isNumber(c)) return ((Number)o).floatValue();
		if (isString(c)) try{if(((String)o).equals("")) return 0;return Float.valueOf((String)o);} catch (NumberFormatException e) {throw new ConvertException(e);}
		throw new ConvertException("不支持该类型到float的转换:"+o.getClass().getName());
	}
	
	/**
	 * 对象转换成BigDecimal<br>
	 * 构造时用字符串避免计算误差
	 * @param o 对象
	 */
	public static BigDecimal toBigDecimal(Object o) throws ConvertException {
		if (o == null) return new BigDecimal(0);
		Class c=o.getClass();
		if (isByte(c)) return new BigDecimal(o.toString());
		if (isShort(c)) return new BigDecimal(o.toString());
		if (isInt(c)) return new BigDecimal(o.toString());
		if (isLong(c)) return new BigDecimal(o.toString());
		if (isFloat(c)) return new BigDecimal(o.toString());
		if (isDouble(c)) return new BigDecimal(o.toString());
		if (isBigDecimal(c)) return ((BigDecimal)o);
		if (isBigInteger(c)) return new BigDecimal(o.toString());
		if (isString(c)) {if(((String)o).equals("")) o="0";return new BigDecimal((String)o);}
		throw new ConvertException("不支持该类型到BigDecimal的转换:"+o.getClass().getName());
	}
	
	/** 
	 * 对象转换成BigInteger
	 * @param o 对象
	 */
	public static BigInteger toBigInteger(Object o) throws ConvertException{
		if (o == null) return BigInteger.valueOf(0);
		Class c=o.getClass();
		if (isByte(c)) return new BigInteger(o.toString());
		if (isShort(c)) return new BigInteger(o.toString());
		if (isInt(c)) return new BigInteger(o.toString());
		if (isLong(c)) return new BigInteger(o.toString());
		if (isFloat(c)) return new BigInteger(o.toString());
		if (isDouble(c)) return new BigInteger(o.toString());
		if (isBigDecimal(c)) return BigInteger.valueOf(((BigDecimal)o).longValue());
		if (isBigInteger(c)) return ((BigInteger)o);
		if (isString(c)) {if(((String)o).equals("")) o="0";return new BigInteger((String)o);}
		throw new ConvertException("不支持该类型到BigInteger的转换:"+o.getClass().getName());
	}
	
	/** 
	 * 对象转成数字类型
	 * @param o
	 * @param 数字具体类型
	 */
	public static Object toNumber(Object obj,Class clazz) throws ConvertException{
		if(obj==null) return null;
		if (obj.getClass().equals(clazz.getClass())) return obj;
		//如果是基础类型及封装类关系
		if (clazz.isPrimitive() && getEncapClass(clazz).equals(obj.getClass())
				||obj.getClass().isPrimitive() && getEncapClass(obj.getClass()).equals(clazz)) return obj;
		
		Object o = null;
		if (isInt(clazz)) return NumberUtils.toInt(obj);
		else if (isLong(clazz)) return NumberUtils.toLong(obj);
		else if (isDouble(clazz)) return NumberUtils.toDouble(obj);
		else if (isByte(clazz)) return NumberUtils.toByte(o);
		else if (isBigDecimal(clazz)) return NumberUtils.toBigDecimal(o);
		else if (isFloat(clazz)) return NumberUtils.toFloat(obj);
		else if (isShort(clazz)) return NumberUtils.toShort(o);
		else if (isBigInteger(clazz)) return NumberUtils.toBigInteger(o);
		return o;
	}
	
	/******************************************************************************************************************
	 * 
	 *  Format 区域
	 * 
	 *******************************************************************************************************************/
	
	/**
	 * 格式化
	 * 
	 * @param obj 数字
	 * @param significant 有效位
	 */
	public static String format(double num, int significant) {
		return getFormat(significant).format(num);
	}

	/**
	 * 格式化
	 * 
	 * @param num 数字
	 * @param significant 有效位
	 * @return
	 */
	public static String format(int num, int significant) {
		return getFormat(significant).format(num);
	}

	/**
	 * 格式化
	 * 
	 * @param num 数字
	 * @param significant 有效位
	 * @return
	 */
	public static String format(String num, int significant) {
		return getFormat(significant).format(Double.valueOf(num));
	}

	/**
	 * 获取DecimalFormat
	 * 
	 * @param significant 有效位
	 * @return
	 */
	public static DecimalFormat getFormat(int significant) {
		StringBuffer sb = new StringBuffer("##0");
		for (int i = 0; i < significant; i++) {
			if (i == 0) sb.append(".");
			sb.append("0");
		}
		return new DecimalFormat(sb.toString());
	}

	/**
	 * 是否为数字
	 * 
	 * @param strNum
	 */
	public static boolean isNumberString(String strNum) {
		return strNum.matches("-?\\d+(\\.\\d+)?");
	}
	
	/**
	 * 是否为整数
	 * @param strNum 字符串数字
	 * @return
	 */
	public static boolean isIntString(String strNum){
		return isIntString(strNum, true);
	}
	
	/**
	 * 是否为整数
	 * @param strNum 字符串数字
	 * @param withSign 是否带符号
	 */
	public static boolean isIntString(String strNum,boolean withSign){
		return withSign?strNum.matches("-?\\d+"):strNum.matches("\\d+");
	}
	
	/**
	 * 获取随机数
	 * @param length 位数
	 */
	public static String getRandomNum(int length){
		int num=new Random().nextInt();
		return StringUtils.fillEmptyWithStr(num, length, "0");
	}
	
	/** 求最小值 */
	public static int min(int... nums){
		int num=nums[0];
		for (int i = 1; i < nums.length; i++) {
			num=Math.min(num, nums[i]);
		}
		return num;
	}
	
	/** 求最大值 */
	public static int max(int... nums){
		int num=nums[0];
		for (int i = 1; i < nums.length; i++) {
			num=Math.max(num, nums[i]);
		}
		return num;
	}
	
}
